#include <jni.h>
#include <string>
#include <android/bitmap.h>

extern "C" {
//使用C语言编译这个文件
#include "gif_lib.h"
}

struct GifBean {
    int current_frame;//当前的帧数
    int total_frame;//全部的帧数
    int *dalay;//每一帧的时长数组
};
#define  argb(a,r,g,b) ( ((a) & 0xff) << 24 ) | ( ((b) & 0xff) << 16 ) | ( ((g) & 0xff) << 8 ) | ((r) & 0xff)
extern "C"
JNIEXPORT jlong JNICALL
//Java+包名+类名+方法名  中间分隔用下划线
// 参数   第一个 JNIEnv  第二个  如static   class   对象  object 第三个开始是需要   传递
Java_com_example_gifload_GifHandler_loadGif(JNIEnv *env, jclass clazz, jstring jpath) {
    //把java的string 转化成C的char数组 须释放
    const char *path = env->GetStringUTFChars(jpath, 0);
    int error;//接受返回的结果
    GifFileType *gifFileType = DGifOpenFileName(path, &error);//通过路径打开gif文件
    DGifSlurp(gifFileType);//初始化缓冲区
    GifBean *gifBean = static_cast<GifBean *>(malloc(sizeof(GifBean)));//申请内存
    memset(gifBean, 0, sizeof(GifBean));//初始化这片内存
    gifFileType->UserData = gifBean;
    gifBean->current_frame = 0;
    gifBean->total_frame = gifFileType->ImageCount;
    env->ReleaseStringUTFChars(jpath, path);//释放转化的char数组
    return reinterpret_cast<jlong>(gifFileType);//强转成long返回
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_example_gifload_GifHandler_getWidth(JNIEnv *env, jclass clazz, jlong gif_handler) {
    GifFileType *gifFileType = reinterpret_cast<GifFileType *>(gif_handler);//强转成giffiletype
    return gifFileType->SWidth;
}extern "C"
JNIEXPORT jint JNICALL
Java_com_example_gifload_GifHandler_getHeight(JNIEnv *env, jclass clazz, jlong gif_handler) {
    GifFileType *gifFileType = reinterpret_cast<GifFileType *>(gif_handler);//强转成giffiletype
    return gifFileType->SHeight;
}

//绘制一帧的图
void drawFrame(GifFileType *gifFileType, AndroidBitmapInfo bitmapInfo, void *pixels) {
    GifBean *gifBean = static_cast<GifBean *>(gifFileType->UserData);
    SavedImage savedImage = gifFileType->SavedImages[gifBean->current_frame];//拿到当前帧的图像序列
    GifImageDesc &desc = savedImage.ImageDesc;//获取图片的信息
    ColorMapObject *pColorMapObject = desc.ColorMap;//获取颜色字典表
    //存放每一行的首地址
    int *px = (int *) pixels;
    int *line;//行索引
    int pointPixel;//每一行的像素索引  使用int，像素是用4个字节存储
    GifByteType byteType;
    GifColorType colorType;
    for (int y = desc.Top; y < desc.Height + desc.Top; ++y) {//y轴，不一定是从0开始的，所以从top开始
        line = px;
        for (int x = desc.Left; x < desc.Left + desc.Width; ++x) {
            //定位像素
            pointPixel = (y - desc.Top) * desc.Width + (x - desc.Left);
            byteType = savedImage.RasterBits[pointPixel];//找出当前像素点的rgb
            colorType = pColorMapObject->Colors[byteType];//根据rgb找出对应的颜色
            line[x] = argb(255,colorType.Red,colorType.Green,colorType.Blue);
        }
        //遍历完一行，转到下一行
        //stride是每行的字节数 先转成字节数相加，再转成int
        px = (int *) ((char *) px + bitmapInfo.stride);
    }
}

extern "C"
JNIEXPORT jint JNICALL
Java_com_example_gifload_GifHandler_updateFrame(JNIEnv *env, jclass clazz, jlong gif_handler,
                                                jobject bitmap) {
    GifFileType *gifFileType = reinterpret_cast<GifFileType *>(gif_handler);
    //根据Android的bitmap.h文件获取宽高
    AndroidBitmapInfo bitmapInfo;
    AndroidBitmap_getInfo(env, bitmap, &bitmapInfo);
    int width = bitmapInfo.width;
    int height = bitmapInfo.height;
//    bitmapInfo.stride;//一行的像素个数   假设是1920*1080  stride是1920*4
    void *pixels;//存放bitmap的像素二维数组
//bitmap--->像素二维数组    ----- 锁住当前bitmap
    AndroidBitmap_lockPixels(env, bitmap, &pixels);
    //绘制
    drawFrame(gifFileType, bitmapInfo, pixels);
    AndroidBitmap_unlockPixels(env, bitmap);//解锁bitmap
    GifBean *gifBean = static_cast<GifBean *>(gifFileType->UserData);
    gifBean->current_frame++;
    if (gifBean->current_frame > gifBean->total_frame - 1) {
        gifBean->current_frame = 0;
    }
    return 100;
}